package com.easylinkin.sm.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.easylinkin.sm.constant.DictItemConstant.Error;
import com.easylinkin.sm.constant.LogConstant.Module;
import com.easylinkin.sm.entity.DictItem;
import com.easylinkin.sm.entity.DictItem.Fields;
import com.easylinkin.sm.mapper.DictItemMapper;
import com.easylinkin.sm.repository.DictItemRepository;
import com.easylinkin.sm.service.DictItemService;
import com.easylinkin.sm.service.I18nService;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import site.morn.boot.data.CrudServiceSupport;
import site.morn.boot.jpa.SpecificationFunction;
import site.morn.boot.rest.RestPage;
import site.morn.core.CriteriaMap;
import site.morn.exception.ApplicationMessages;
import site.morn.log.OperateArguments;
import site.morn.rest.RestModel;
import site.morn.rest.RestPageable;

/**
 * 数据字典服务
 *
 * @author wujie
 * @since 0.1.1,  2019/08/19
 */
@Slf4j
@Service
@Transactional
public class DictItemServiceImpl extends
    CrudServiceSupport<DictItem, Long, DictItemRepository> implements
    DictItemService {

  @Autowired
  private I18nService i18nService;

  @Autowired
  private DictItemMapper dictItemMapper;

  @Override
  public <S extends DictItem> S add(RestModel<S> restModel) {
    S model = restModel.getModel();
    this.codeValidate(model.getCode());
    this.nameValidate(model.getDictId(), model.getName());

    S one = super.add(restModel);
    OperateArguments.add(model.getName());
    i18nService.saveI18n(restModel.getAttach(), one.getId(), Module.DICT_ITEM);
    return one;
  }

  @Override
  public <S extends DictItem> S update(RestModel<S> restModel) {
    S model = restModel.getModel();
    this.codeValidate(model.getId(), model.getCode());
    this.nameValidate(model.getDictId(), model.getName(), model.getId());
    //修改时先删除关联国际化
    OperateArguments.add(model.getName());
    this.deleteDictI18n(restModel.getModel().getId());
    i18nService.saveI18n(restModel.getAttach(), null, Module.DICT_ITEM);
    return super.update(restModel);
  }

  @Override
  public List<DictItem> findParentDicItemList(Long id) {
    Locale locale = LocaleContextHolder.getLocale();
    List<DictItem> lis = dictItemMapper
        .findParentDicItemList(id, Module.DICT_ITEM, locale.toString().toUpperCase());
    return lis;
  }

  @Override
  public List<DictItem> findDicItemList(String dictCode) {
    Locale locale = LocaleContextHolder.getLocale();
    return dictItemMapper
        .findDicItemList(dictCode, Module.DICT_ITEM, locale.toString().toUpperCase());
  }

  @Override
  public Page<DictItem> getDictItemPage(RestPage<DictItem> restPage) {
    RestPageable pageable = restPage.getPageable();
    DictItem model = restPage.getModel();
    Page page = new Page(pageable.getPage() + 1, pageable.getSize());
    String language = LocaleContextHolder.getLocale().toString().toUpperCase();

    List<DictItem> departments = dictItemMapper
        .getDictItemPage(model, language, Module.DICT_ITEM, page);
    page.setRecords(departments);
    return page;
  }

  @Override
  public void delete(Long id) {
    //子节点校验
    this.childNodeValidate(id);
    //删除国际化
    this.deleteDictI18n(id);
    super.delete(id);
  }

  @Override
  public List<Long> batchDelete(List<Long> ids) {
    List<Long> list = new ArrayList<>();
    ids.forEach(x -> {
      try {
        this.delete(x);
      } catch (Exception e) {
        log.error("error", e);
        list.add(x);
      }
    });
    return list;
  }

  @Override
  protected SpecificationFunction searchSpecificationFunction(DictItem model,
      CriteriaMap attach) {
    return (reference, restrain, predicate) ->
        restrain
            .appendAnd(predicate.contains(DictItem.Fields.name, DictItem.Fields.code))
            .appendAnd(predicate.eq(Fields.dictId))
            .appendAnd(predicate.eq(Fields.parentId));

  }

  /**
   * 删除数据字典关联的国际化
   *
   * * @param attach 国际化key
   */
  private void deleteDictI18n(Long key) {
    i18nService.deleteByKeyAndModule(key, Module.DICT_ITEM);
  }

  /**
   * 子节点校验
   */
  private void childNodeValidate(Long id) {
    List<DictItem> list = this.repository().findByParentId(id);
    if (!list.isEmpty()) {
      throw ApplicationMessages.translateException(Error.DELETE_FAIL_HASCHILD).exception();
    }
  }

  /**
   * 新增：名称同级校验
   */
  private void nameValidate(Long dictId, String name) {
    List<DictItem> list = this.repository().findByNameAndDictId(name, dictId);
    if (!list.isEmpty()) {
      throw ApplicationMessages.translateException(Error.DICT_NAME_REPEAT).exception();
    }
  }

  /**
   * 修改：名称同级校验
   */
  private void nameValidate(Long dictId, String name, Long id) {
    List<DictItem> list = this.repository().findByNameAndDictIdAndIdNot(name, dictId, id);
    if (!list.isEmpty()) {
      throw ApplicationMessages.translateException(Error.DICT_NAME_REPEAT).exception();
    }
  }

  /**
   * 新增：字典编码唯一校验
   */
  private void codeValidate(String code) {
    List<DictItem> list = this.repository().findByCode(code);
    if (!list.isEmpty()) {
      throw ApplicationMessages.translateException(Error.DICT_CODE_REPEAT).exception();
    }
  }

  /**
   * 修改：字典编码唯一校验
   */
  private void codeValidate(Long id, String code) {
    List<DictItem> list = this.repository().findByCodeAndIdNot(code, id);
    if (!list.isEmpty()) {
      throw ApplicationMessages.translateException(Error.DICT_CODE_REPEAT).exception();
    }
  }
}
